﻿// See https://aka.ms/new-console-template for more information
//Console.WriteLine("Hello, World!");

/*using VisitorPattern;
using VisitorPattern.Visitor;

Console.WriteLine("************************************************");
List<Student> students = new List<Student>();
students.Add(new StudentVip() { Id=123, Name="ME234" });
students.Add(new StudentVip() { Id = 124, Name = "如果" });
students.Add(new StudentFree() { Id = 145, Name = "羽毛" });

VisitorCurrent visitorCurrent = new VisitorCurrent();
VisitorPast visitorPast = new VisitorPast();
foreach (var student in students)
{
    student.Study();

    //student.GetVideo();
    // 这里使用了双重派发
    student.GetVideoVisitor(visitorCurrent);
}
Console.WriteLine("************************************************");
foreach (var student in students)
{
    student.Study();

    //student.GetVideo();
    // 这里使用了双重派发
    student.GetVideoVisitor(visitorPast);
}

Console.WriteLine("************************************************");
VisitorTemp visitorTemp = new VisitorTemp();
foreach (var student in students)
{
    student.Study();

    //student.GetVideo();
    // 这里使用了双重派发
    student.GetVideoVisitor(visitorTemp);
}*/

/*************************************************************
 * 访问者模式的优点是
 * 1 可以对方法进行扩展
 * 2 有不同的版本可以同时存在，根据不同的权限获取不同的逻辑进行处理
 * 缺点：
 * 1 如果类有扩展了或者接口有扩展了就会很麻烦
 * 
 * 适用场景：
 * 适合那些类不怎么改变，但是方法内部会有不同权限分支的程序
 * 访问者模式适用于对象结构相对稳定，但经常需要在此结构上定义新的操作的场景。
 *************************************************************/


// 访问者模式的案例
using VisitorPattern.Samples;

var document = new Document();
document.AddElement(new TextElement { Content = "Hello World" });
document.AddElement(new ImageElement { Url = "pic.jpg" });
document.AddElement(new TableElement { Rows = 3, Columns = 4 });
document.AddElement(new PDFElement() { PDFName = "PDF 高级开发" });
// 导出为 HTML
Console.WriteLine("=== HTML Export ===");
document.Accept(new HtmlExportVisitor());

// 导出为 Markdown
Console.WriteLine("\n=== Markdown Export");
document.Accept(new MarkdownVisitor());

// 导出为PDF
Console.WriteLine("=== PDF ===");
document.Accept(new PDFVisitor());

/**
 * 关键点
双重分发（Double Dispatch）：
通过element.Accept(visitor)调用visitor.VisitXxx(this)，实现元素类型和访问者操作的动态绑定。

开闭原则：

新增导出格式（如PDF）只需添加IVisitor实现类，无需修改元素类。

新增元素类型（如VideoElement）需修改所有访问者（违反开闭原则，需权衡）。

访问者缺点：
如果对象结构不稳定（常新增元素类型），访问者模式可能不适用，因为每新增一个元素都要修改所有访问者。
 */